﻿using FluentValidation;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
//using SharpGrip.FluentValidation.AutoValidation.Mvc.Interceptors;
//using SharpGrip.FluentValidation.AutoValidation.Shared.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EasyCore.Reflection;

namespace EasyCore.DataValidation
{
    public class EasyValidationActionFilter : IAsyncActionFilter
    {
        /// <summary>
        /// 结果工厂类
        /// </summary>
        public IEasyValidationResultFactory ValidationResultFactory { get; private set; }

        /// <summary>
        /// 配置信息
        /// </summary>
        public DataValidationMvcConfiguration Configuration { get; private set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="validationResultFactory"></param>
        /// <param name="options"></param>
        public EasyValidationActionFilter(IEasyValidationResultFactory validationResultFactory, IOptions<DataValidationMvcConfiguration> options)
        {
            this.ValidationResultFactory = validationResultFactory;
            this.Configuration = options.Value;
        }

        /// <summary>
        /// 执行方法
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            //判断当前请求的，是否是控制器类
            if (!IsValidController(context.Controller))
            {
                await next();
                return;
            }
            var endpoint = context.HttpContext.GetEndpoint();//获得请求的终节点
            var controllerActionDescriptor = (ControllerActionDescriptor)context.ActionDescriptor;//获得控制器方法的描述器
            var serviceProvider = context.HttpContext.RequestServices; //获得当前请求的服务容器

            if (endpoint != null && endpoint.Metadata.OfType<DataValidateNeverAttribute>().Any())
            {
                HandleUnvalidatedEntries(context);
                await next();
                return;
            }
            var parameters = controllerActionDescriptor.Parameters; //获得方法的参数
            if (parameters != null && parameters.Any())
            {
                foreach (var parameter in parameters)
                {
                    if (context.ActionArguments.TryGetValue(parameter.Name, out var subject))
                    {
                        var parameterInfo = (parameter as ControllerParameterDescriptor)?.ParameterInfo;
                        var parameterType = subject?.GetType();
                        var bindingSource = parameter.BindingInfo?.BindingSource;
                        if (parameterType != null && parameterType.HasCustomAttribute<DataValidateNeverAttribute>()) continue; //执行下一个参数
                        if (subject == null || parameterType == null || !parameterType.IsCustomType() || !HasValidBindingSource(bindingSource))
                        {
                            continue;
                        }
                        var obj = serviceProvider.GetService(typeof(IValidator<>).MakeGenericType(parameterType));
                        if (obj is IValidator validator)
                        {
                            IValidationContext validationContext = new ValidationContext<object>(subject);
                            var validationResult = await validator.ValidateAsync(validationContext, context.HttpContext.RequestAborted);
                            if (!validationResult.IsValid)
                            {
                                foreach (var error in validationResult.Errors)
                                {
                                    context.ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
                                }
                            }
                        }
                    }
                }
            }

            HandleUnvalidatedEntries(context);
            if (!context.ModelState.IsValid)
            {
                //响应验证失败的结果
                var problemDetailsFactory = serviceProvider.GetRequiredService<ProblemDetailsFactory>();
                var validationProblemDetails = problemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState);
                context.Result = ValidationResultFactory.CreateActionResult(context, validationProblemDetails);
                return;
            }
            await next();
        }

        /// <summary>
        /// 当前访问的类是否是控制器
        /// </summary>
        /// <param name="controller"></param>
        /// <returns></returns>
        private bool IsValidController(object controller)
        {          
            var controllerType = controller.GetType();
            if (controllerType.HasCustomAttribute<NonControllerAttribute>())
            {
                return false;
            }
            return controller is ControllerBase ||
                   controllerType.HasCustomAttribute<ControllerAttribute>() ||
                   controllerType.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) ||
                   controllerType.InheritsFromTypeWithNameEndingIn("Controller");
           
        }

        private bool HasValidBindingSource(BindingSource? bindingSource)
        {
            return (Configuration.EnableBodyBindingSourceValidation && bindingSource == BindingSource.Body) ||
                   (Configuration.EnableFormBindingSourceValidation && bindingSource == BindingSource.Form) ||
                   (Configuration.EnableQueryBindingSourceValidation && bindingSource == BindingSource.Query) ||
                   (Configuration.EnablePathBindingSourceValidation && bindingSource == BindingSource.Path) ||
                   (Configuration.EnableCustomBindingSourceValidation && bindingSource == BindingSource.Custom) ||
                   (Configuration.EnableNullBindingSourceValidation && bindingSource == null);
        }

        /// <summary>
        /// 处理相关实体的状态：当实体对象未验证时，则跳过
        /// </summary>
        /// <param name="context"></param>
        private void HandleUnvalidatedEntries(ActionExecutingContext context)
        {
            if (Configuration.DisableBuiltInModelValidation)
            {
                foreach (var modelStateEntry in context.ModelState.Values.Where(modelStateEntry => modelStateEntry.ValidationState == ModelValidationState.Unvalidated))
                {
                    modelStateEntry.ValidationState = ModelValidationState.Skipped;
                }
            }
        }

    }
}
